home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1990-1992 Michael Davidson.
- * All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation.
- *
- * This software is provided "as is" without express or implied warranty.
- */
-
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <memory.h>
- #include <setjmp.h>
- #include <errno.h>
- #include <signal.h>
- #include <unistd.h>
- #include <sys/types.h>
- #if defined(SVR4)
- #include <sys/kd.h>
- #include <sys/vt.h>
- #define VT_TRUE 1
- #else
- #include <sys/vtkd.h>
- #endif
-
- #include "video.h"
- #include "vbios.h"
- #include "vdev.h"
-
- /*
- * color palette
- */
- unsigned Black;
- unsigned White;
-
- /*
- * 8 x 14 Font
- */
- font_t *Font8x14;
- font_t *DefaultFont;
-
- /*
- * Pixel lookup table for 8 bit displays
- */
- unsigned char VPixelLookup[32 * 1024];
-
- /*
- * Text mode screen
- */
- static unsigned char *TextScreen = NULL;
- static int TextMode = -1;
- static vmode_t *TextModeInfo = NULL;
- static void textRedraw();
-
- /*
- * screen switch handling
- */
- STATIC int vidCheckDisplayed();
-
- STATIC int video_flags = 0;
-
- #define VIDEO_DISPLAYED 0x01
- #define VIDEO_SWITCH_AWAY 0x02
- #define VIDEO_SWITCH_BACK 0x04
-
-
- STATIC int video_fd = 0;
-
- STATIC vdev_t video_dev;
- STATIC int VideoMode = -1;
- STATIC vmode_t *VideoModeInfo = NULL;
-
- STATIC void switch_away(int);
- STATIC void switch_back(int);
- STATIC void vidRedraw();
-
- STATIC int vidNull();
-
- STATIC int (*graphicsRedraw)() = vidNull;
-
- STATIC void vidDevInit(char *name, vdev_t *vdevp);
-
- /*
- * display initialisation
- */
- void
- vidInit(
- char *display
- )
- {
- struct vt_mode smode;
- static font_t vga_8x14;
-
- video_fd = 0;
-
- /*
- * must be root or setuid root to run this
- */
- if (geteuid() != 0)
- fatal(0, "must be root or setuid root");
-
- /*
- * set up signal handlers for screen switching
- */
- smode.mode = VT_PROCESS;
- smode.waitv = 0;
- smode.relsig = SIGUSR1;
- smode.acqsig = SIGUSR2;
- smode.frsig = SIGINT;
-
- signal(SIGUSR1, switch_away);
- signal(SIGUSR2, switch_back);
- if (ioctl(video_fd, VT_SETMODE, &smode) != 0)
- fatal(errno, "can't set screen-switch handlers");
-
- /*
- * check that this process is running on the currently
- * displayed screen and, if necessary, wait until this
- * screen is switched to
- */
- while (ioctl(video_fd, VT_RELDISP, VT_ACKACQ) < 0)
- pause();
-
- if (ioctl(video_fd, KDSETMODE, KD_GRAPHICS) != 0)
- fatal(errno, "can't set display to graphics mode");
-
- if (VBiosInit() != 0)
- fatal(errno, "can't initialise video BIOS");
-
- vidDevInit(display, &video_dev);
-
- if ((vga_8x14.f_data = (unsigned char *)VBiosGetFontInfo(2)) == NULL)
- fatal(0, "can't access VGA 8x14 font");
- vga_8x14.f_width = 8;
- vga_8x14.f_height = 14;
-
- Font8x14 = &vga_8x14;
- DefaultFont = Font8x14;
-
- video_flags = VIDEO_DISPLAYED;
-
- }
-
- STATIC void
- vidDevInit(
- char *name,
- vdev_t *vdevp
- )
- {
- struct vdevinit *d;
-
- if (name != NULL)
- {
- for (d = vdevsw; d->name != NULL; d++)
- {
- if (strcmp(name, d->name) == 0)
- {
- if ((*d->init)(name, vdevp) == 0)
- return;
- fatal(0, "initialisation of display type '%s' failed", name);
- }
- }
- fatal(0, "display type '%s' not supported", name);
- }
-
- /*
- * try to auto-detect
- */
- for (d = vdevsw; d->name != NULL; d++)
- {
- if ((*d->probe)() > 0)
- {
- if ((*d->init)(name, vdevp) == 0)
- return;
- fatal(0, "initialisation of display type '%s' failed", name);
- }
- }
-
- fatal(0, "auto-detection failed: cannot determine display type");
- }
-
- /*
- * display reset
- */
- void
- vidReset()
- {
- struct vt_mode smode;
-
- if (vidCheckDisplayed())
- (*video_dev.v_reset)();
-
- if (ioctl(video_fd, KDSETMODE, KD_TEXT) != 0)
- fatal(errno, "can't set display to text mode");
-
- write(video_fd, "\f", 1);
-
- smode.mode = VT_AUTO;
- smode.waitv = 0;
- smode.relsig = 0;
- smode.acqsig = 0;
- smode.frsig = 0;
- ioctl(video_fd, VT_SETMODE, &smode);
- signal(SIGUSR1, SIG_IGN);
- signal(SIGUSR2, SIG_IGN);
- }
-
- /*
- * vidGetModes() - returns pointer to table of supported modes
- */
- vmode_t *
- vidGetModes()
- {
- return video_dev.v_modes;
- }
-
- /*
- * vidModeInfo() - returns pointer to information for the mode specified
- */
- vmode_t *
- vidModeInfo(
- int i
- )
- {
- return &((vmode_t *)video_dev.v_modes)[i];
- }
-
- /*
- * vidGetName() - returns display name
- */
- char *
- vidGetName()
- {
- return video_dev.v_name;
- }
-
- /*
- * vidSetMode() - sets display mode
- */
- int
- vidSetMode(
- int i
- )
- {
- if (vidCheckDisplayed())
- if ((*video_dev.v_setmode)(i) != 0)
- return -1;
-
- VideoMode = i;
- VideoModeInfo = vidModeInfo(i);
-
- if (VideoModeInfo->flags & V_TEXT_MODE)
- {
- if (i == TextMode)
- {
- textRedraw();
- }
- else
- {
- vmode_t *m = VideoModeInfo;
-
- if (TextScreen)
- free(TextScreen);
-
- if ((TextScreen = calloc(m->width * m->height, 2)) == NULL)
- fatal(errno, "can't allocate memory for %d x %d text screen",
- m->width, m->height);
-
- TextMode = i;
- TextModeInfo = m;
- }
- }
-
- Black = 0;
- White = 1;
-
- return 0;
- }
-
- /*
- * vidGetMode() - returns current display mode
- */
- vidGetMode()
- {
- return VideoMode;
- }
-
- /*
- * vidClear()
- */
- void
- vidClear(
- unsigned color
- )
- {
- if (vidCheckDisplayed())
- (*video_dev.v_clear)(color);
-
- if (VideoMode == TextMode)
- memset(TextScreen, color | (color << 4),
- TextModeInfo->width * TextModeInfo->height * 2);
- }
-
- /*
- * vidSetPalette() - sets video palette
- */
- void
- vidSetPalette(
- color_t *colormap,
- int ncolors
- )
- {
- int i;
- unsigned l, lmax, lmin;
-
- if (vidCheckDisplayed())
- (*video_dev.v_setpalette)(colormap, ncolors);
-
- lmax = 0;
- lmin = 255;
-
-
- for (i = 0; i < ncolors; i++, colormap++)
- {
- l = colormap->red * 77;
- l += colormap->green * 150;
- l += colormap->blue * 29;
- l /= 256;
-
- if (l > lmax)
- {
- lmax = l;
- White = i;
- }
-
- if (l < lmin)
- {
- lmin = l;
- Black = i;
- }
- }
- }
-
- /*
- * vidPutPixels8() - writes 8 bit pixels to the display
- * - note that PutPixels() can be used to write
- * at most one scanline at a time and that it
- * clips to the actual size of the display in
- * the current mode
- */
- vidPutPixels8(
- int x,
- int y,
- pixel8_t *pixbuf,
- int npixels
- )
- {
- if (y >= VideoModeInfo->height)
- return 0;
-
- if (x >= VideoModeInfo->width)
- return 0;
-
- if (x+npixels > VideoModeInfo->width)
- npixels = VideoModeInfo->width - x;
-
- if (vidCheckDisplayed())
- (*video_dev.v_putpixels8)(x, y, pixbuf, npixels);
-
- return npixels;
- }
-
- /*
- * vidPutPixels24() - writes 24 bit pixels to the display
- * - note that PutPixels() can be used to write
- * at most one scanline at a time and that it
- * clips to the actual size of the display in
- * the current mode
- */
- vidPutPixels24(
- int x,
- int y,
- pixel24_t *pixbuf,
- int npixels
- )
- {
- if (y >= VideoModeInfo->height)
- return 0;
-
- if (x >= VideoModeInfo->width)
- return 0;
-
- if (x+npixels > VideoModeInfo->width)
- npixels = VideoModeInfo->width - x;
-
- if (vidCheckDisplayed())
- (*video_dev.v_putpixels24)(x, y, pixbuf, npixels);
-
- return npixels;
- }
-
- /*
- * vidPutText() - writes text to the display when in text mode
- */
- void
- vidPutText(
- int x,
- int y,
- char *buf,
- int nbytes,
- int fg,
- int bg
- )
- {
- unsigned char *p;
- unsigned char attr;
- int n;
-
- if (VideoMode != TextMode)
- return;
-
- p = TextScreen + ((y * TextModeInfo->width) + x) * 2;
- attr = (fg & 0x0f) | ((bg & 0x0f) << 4);
- n = nbytes;
-
- while (--n >= 0)
- {
- *p++ = *buf++;
- *p++ = attr;
- }
-
- p = TextScreen + ((y * TextModeInfo->width) + x) * 2;
- if (vidCheckDisplayed())
- (*video_dev.v_puttext)(x, y, p, nbytes * 2);
- }
-
- /*
- * vidDrawText() - draws text on the display when in graphics mode
- */
- void
- vidDrawText(
- int x,
- int y,
- char *text,
- int len,
- font_t *font
- )
- {
- unsigned char c;
- int i, j, k, l;
- unsigned char *f, *p, pix;
- void *pixels;
- int n;
- int w;
- int fg;
- int bg;
- int bpp;
- extern void *alloca(int);
-
- if (! (VideoModeInfo->flags & V_GRAPHICS_MODE))
- return;
-
- if (VideoModeInfo->depth <= 8)
- {
- bpp = 1;
- fg = White;
- bg = Black;
- }
- else
- {
- bpp = 3;
- fg = 0xff;
- bg = 0x00;
- }
-
- n = len * font->f_width;
- pixels = alloca(n * bpp);
- w = (font->f_width + 7) / 8;
-
- for (i = 0; i < font->f_height; i++)
- {
- p = pixels;
- for (j = 0; j < len; j++)
- {
- c = text[j];
-
- f = font->f_data + w * (c * font->f_height + i);
- for (k = 0; k < font->f_width; k++)
- {
- if ((k & 7) == 0)
- c = *f++;
- pix = (c & 0x80) ? fg : bg;
- for (l = 0; l < bpp; l++)
- *p++ = pix;
- c <<= 1;
- }
- }
- if (bpp == 1)
- vidPutPixels8(x, y + i, pixels, n);
- else
- vidPutPixels24(x, y + i, pixels, n);
- }
- }
-
- void
- vidSetGraphicsRedraw(
- int (*redraw)()
- )
- {
- graphicsRedraw = redraw;
- }
-
- STATIC int
- vidNull()
- {
- return 0;
- }
-
- void
- textRedraw()
- {
- int i;
-
- if (VideoMode != TextMode)
- return;
-
- for (i = 0; i < TextModeInfo->height; i++)
- {
- if (vidCheckDisplayed())
- (*video_dev.v_puttext)(0, i, TextScreen + TextModeInfo->width * i * 2,
- TextModeInfo->width * 2);
- }
- }
-
- STATIC int
- vidCheckDisplayed()
- {
- (void) vidCheckScreenSwitch(0);
-
- return (video_flags & VIDEO_DISPLAYED);
- }
-
- /*
- * vidCheckScreenSwitch(block) - handle pending screen switch request
- * - if "block" is true then requests to
- * switch away will block here until a
- * switch back occurs
- * - returns 0 if there is no screen switch
- * - returns 1 if a screen switch occurred
- */
- int
- vidCheckScreenSwitch(
- int block
- )
- {
- if (! (video_flags & (VIDEO_SWITCH_AWAY | VIDEO_SWITCH_BACK)) )
- return 0;
-
- if (video_flags & VIDEO_SWITCH_AWAY)
- {
- if (video_flags & VIDEO_DISPLAYED)
- (*video_dev.v_reset)();
-
- if (ioctl(video_fd, KDSETMODE, KD_TEXT) != 0)
- fatal(errno, "can't set display to text mode");
-
- video_flags &= ~(VIDEO_SWITCH_AWAY | VIDEO_DISPLAYED);
-
- ioctl(video_fd, VT_RELDISP, VT_TRUE);
-
- /*
- * if we do not want to block return immediately and
- * indicate that a screen-switch has taken place
- */
- if (block == 0)
- return 1;
-
- while (! (video_flags & VIDEO_SWITCH_BACK))
- pause();
- }
-
- if (video_flags & VIDEO_SWITCH_BACK)
- {
- video_flags &= ~VIDEO_SWITCH_BACK;
-
- ioctl(video_fd, VT_RELDISP, VT_ACKACQ);
-
- video_flags |= VIDEO_DISPLAYED;
-
- if (ioctl(video_fd, KDSETMODE, KD_GRAPHICS) != 0)
- fatal(errno, "can't set display to graphics mode");
-
- (*video_dev.v_setmode)(VideoMode);
-
- vidRedraw();
- }
-
- return 1;
- }
-
- /*
- * vidRedraw() - called from screen switch handling to redraw the screen
- * Since another screen switch can occur while the redraw
- * is in progress vidRedraw() traps any recursive calls to
- * itself and unwinds the stack to the top level. This
- * means that functions called by vidRedraw() must not allocate
- * any resources.
- */
- STATIC void
- vidRedraw()
- {
- static int redraw_in_progress = 0;
- static jmp_buf redraw_unwind;
-
- if (redraw_in_progress)
- longjmp(redraw_unwind, 1);
-
- setjmp(redraw_unwind);
- redraw_in_progress = 1;
-
- /*
- * NOTE: actually do the redraw here
- * the mode has already been set - need to reset the palette
- * and redraw the screen
- */
- if (VideoModeInfo->flags & V_TEXT_MODE)
- textRedraw();
- else
- (void)graphicsRedraw();
-
- redraw_in_progress = 0;
- }
-
- /*
- * screen switch signal handlers
- */
-
- STATIC void
- switch_away(
- int sig
- )
- {
- signal(sig, switch_away);
- video_flags |= VIDEO_SWITCH_AWAY;
- }
-
- STATIC void
- switch_back(
- int sig
- )
- {
- signal(sig, switch_back);
- video_flags |= VIDEO_SWITCH_BACK;
- }
-
-